package com.hzj.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

//链式编程
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = "customUserService")
    UserDetailsService uds;
    @Autowired
    DataSource datasource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(datasource);
        //设置自动创建数据表
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }


    // 设置页面访问权限
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("执行了设置页面访问权限方法");
        http.authorizeRequests().antMatchers("/").permitAll()//表示该页面所有用户可以访问
                .antMatchers("/admin/**").hasRole("admin")//设置只有指定用户才能访问对应的页面
                .antMatchers("/admin/admin/**").hasAnyAuthority("admin", "user")////设置指定权限可以访问
                //其实hasRole与hasAnyAuthority俩个方法差不多只是 hasRole，在赋予权限时会在字段前加上ROLE_字段(具体看源码)
                .and()

                .formLogin().loginPage("/login.html")//自定义登录页面
                .defaultSuccessUrl("/cg")//设置登录成功后跳转的页面
                .loginProcessingUrl("/login")//form表单action="/login"提交页面
                .usernameParameter("username")//表单用户name属性值
                .passwordParameter("password")//表单密码name属性值

// 注销
                //关闭csrf功能，登录失败可能存在的原因
                .and()
                .logout().logoutSuccessUrl("/login.html")//开启注销功能,logoutSuccessUrl("/index")注销成功跳转到指定页面
                .and()
                .rememberMe()//开启记住我
//                .rememberMeParameter("remember")//设置记住我属性名，默认为remember-me
                .tokenRepository(persistentTokenRepository())
//                .tokenValiditySeconds(60)//设置过期时长
                .userDetailsService(uds)
                .and()
                //设置没用权限跳转到指定页面
                .exceptionHandling()
                .accessDeniedPage("/home.html");
        http.csrf().disable();
    }

    @Override
//认证与授权，为用户添加权限
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("执行了认证与授权方法");
        //下面这些方法只能使用死的用户名，想要更多功能得自定义一个UserDetailsService类，uds是自定义的UserDetailsService类，具体看UserDetailsService这个章节
        auth.userDetailsService(uds).passwordEncoder(new BCryptPasswordEncoder());

//        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder());

//        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())//设置密码加密，Security5+版本必写，不然报错There is no PasswordEncoder mapped for the id "null"
//                .withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("admin", "vip2");

//                .and()
//                .withUser("aaa").password(new BCryptPasswordEncoder().encode("aaa")).roles("vip1");
    }

    @Override
//认证与授权
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }
}